/*
 * Copyright 2003-2006 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.nanhill.commons.id;

import java.lang.reflect.InvocationTargetException;

import org.nanhill.commons.id.uuid.UUID;

/**
 * Abstract factory for identifier generator instances.
 * 
 * <p>
 * Use newInstance() to get a concrete factory instance.
 * </p>
 * 
 * <p>
 * Commons Discovery is used to select the concrete factory. The default factory
 * is {@link DefaultIdentifierGeneratorFactory}, which can be subclassed (or
 * replaced) to plug in alternative identifier implementations. See <a
 * href="http://jakarta.apache.org/commons/discovery/">Commons Discovery
 * Documentation</a> for instructions on how to set up discovery for
 * user-supplied factories.
 * </p>
 * 
 * @author Commons-id team
 * 
 * @version $Id: IdentifierGeneratorFactory.java,v 1.1 2006/09/20 06:55:58 alin Exp $
 */
public abstract class IdentifierGeneratorFactory {
	/**
	 * Default constructor.
	 */
	protected IdentifierGeneratorFactory() {
		super();
	}

	/**
	 * Create an instance of an <code>IdentifierGeneratorFactory</code>.
	 * 
	 * @return a new factory
	 */
	public static IdentifierGeneratorFactory newInstance() {
		return new DefaultIdentifierGeneratorFactory();
	}

	/**
	 * Gets a new {@link LongIdentifierGenerator} that generates a sequence of
	 * Long objects increasing in value.
	 * 
	 * <p>
	 * The sequence will wrap when the maximum <code>long</code> value is
	 * reached and return negative numbers. It will start from zero.
	 * </p>
	 * 
	 * @return a new LongIdentifier with wrapping behavior
	 */
	public abstract LongIdentifierGenerator longGenerator();

	/**
	 * Gets a new {@link LongIdentifierGenerator} that generates a sequence of
	 * Long objects increasing in value.
	 * 
	 * @param wrap
	 *            should the sequence wrap when it reaches the maximum long
	 *            value (or throw an {@link IllegalStateException})
	 * @param initialValue
	 *            the initial long value to start at
	 * @return a new LongIdentifier with the specified properties
	 */
	public abstract LongIdentifierGenerator longGenerator(boolean wrap,
			long initialValue);

	/**
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size.
	 * 
	 * <p>
	 * The sequence will wrap when the maximum <code>long</code> value is
	 * reached and return negative numbers. It will start from zero.
	 * </p>
	 * 
	 * @return a new StringIdentifierGenerator
	 */
	public abstract StringIdentifierGenerator numericGenerator();

	/**
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size.
	 * 
	 * @param wrap
	 *            should the sequence wrap when it reaches the maximum long
	 *            value (or throw an IllegalStateException)
	 * @param initialValue
	 *            the initial long value to start at
	 * @return a new StringIdentifierGenerator
	 */
	public abstract StringIdentifierGenerator numericGenerator(boolean wrap,
			long initialValue);

	/**
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size, prefixed by an
	 * initial string.
	 * 
	 * @param prefix
	 *            prefix, must not be null
	 * @param wrap
	 *            should the sequence wrap when it reaches the maximum long
	 *            value (or throw an IllegalStateException)
	 * @param initialValue
	 *            the initial long value to start at
	 * @return a new StringIdentifierGenerator
	 * @throws IllegalArgumentException
	 *             if prefix is null
	 */
	public abstract StringIdentifierGenerator prefixedNumericGenerator(
			String prefix, boolean wrap, long initialValue);

	/**
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size, prefixed by an
	 * initial string and left-padded to make all strings the same length.
	 * 
	 * @param prefix
	 *            prefix, must not be null or empty
	 * @param wrap
	 *            should the factory wrap when it reaches the maximum value that
	 *            can be represented in <code>size</code> base 10 digits (or
	 *            throw an exception)
	 * @param size
	 *            the size of the identifier, including prefix length
	 * @return a new StringIdentifierGenerator
	 * @throws IllegalArgumentException
	 *             if prefix is null or size less prefix length is less than 1
	 */
	public abstract StringIdentifierGenerator prefixedLeftPaddedNumericGenerator(
			String prefix, boolean wrap, int size);

	/**
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size in base-36.
	 * 
	 * <p>
	 * The sequence will wrap when the maximum size (15) is reached.
	 * </p>
	 * 
	 * @return a new StringIdentifierGenerator
	 */
	public abstract StringIdentifierGenerator alphanumericGenerator();

	/**
	 * Gets a new {@link StringIdentifierGenerator} that generates an
	 * incrementing number in base 36 with a prefix as a String object.
	 * 
	 * @param prefix
	 *            prefix, must not be null
	 * @param wrap
	 *            should the factory wrap when it reaches the maximum value that
	 *            can be represented in <code>size</code> base 36 digits (or
	 *            throw an exception)
	 * @param size
	 *            the size of the identifier, including prefix length
	 * @return a new StringIdentifierGenerator
	 * @throws IllegalArgumentException
	 *             if prefix is null or size less prefix length is not at least
	 *             one
	 */
	public abstract StringIdentifierGenerator prefixedAlphanumericGenerator(
			String prefix, boolean wrap, int size);

	/**
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size in base-36.
	 * 
	 * @param wrap
	 *            should the factory wrap when it reaches the maximum size (or
	 *            throw an IllegalStateException)
	 * @param size
	 *            the number of characters the id should fill
	 * @return a new StringIdentifierGenerator
	 */
	public abstract StringIdentifierGenerator alphanumericGenerator(
			boolean wrap, int size);

	/**
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size in base-36,
	 * starting at an initial value.
	 * 
	 * @param wrap
	 *            should the factory wrap when it reaches the maximum size (or
	 *            throw an IllegalStateException)
	 * @param initialValue
	 *            the initial value to start at
	 * @return a new StringIdentifierGenerator
	 */
	public abstract StringIdentifierGenerator alphanumericGenerator(
			boolean wrap, String initialValue);

	/**
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects that appear to be random and are suitable for use as
	 * session identifiers.
	 * 
	 * @return a new StringIdentifierGenerator
	 */
	public abstract StringIdentifierGenerator sessionIdGenerator();

	/**
	 * Gets a new {@link IdentifierGenerator} that generates version one UUID
	 * objects that conform to the <a
	 * href="http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-02.txt">
	 * IETF Draft UUID specification</a>.
	 * 
	 * @return a new IdentifierGenerator that generates version one UUIDs.
	 * @throws NoSuchMethodException
	 *             exception thrown while instantiating the generator.
	 * @throws InvocationTargetException
	 *             exception thrown while instantiating the generator.
	 * @throws IllegalAccessException
	 *             exception thrown while instantiating the generator.
	 * @throws InstantiationException
	 *             exception thrown while instantiating the generator.
	 */
	public abstract IdentifierGenerator<UUID> uuidVersionOneGenerator()
			throws NoSuchMethodException, InvocationTargetException,
			IllegalAccessException, InstantiationException;

	/**
	 * Gets a new {@link IdentifierGenerator} that generates version four UUID
	 * Obejcts that conform to the <a
	 * href="http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-02.txt">
	 * IETF Draft UUID specification</a>.
	 * 
	 * @return a new IdentifierGenerator that generates version four UUIDs.
	 */
	public abstract IdentifierGenerator<UUID> uuidVersionFourGenerator();
}
